﻿using System;
using System.Net.Sockets;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace CzfSDK
{
	public class CzfNetManager
	{
		public static CzfNetManager current;

		public bool debug = false;

		public CzfEvent<CzfNetManager, CzfNetClient> OnClientConnect;
		public CzfEvent<CzfNetManager, CzfNetClient> OnClientClose;


		private object allClientLock = new object ();
		public List<CzfNetClient> allClient;


		public CzfNetListener listener;
		public CzfProto proto;
		private int iTimeout;
		private bool looping = true;

		public void Call(CzfNetClient client, string method, string callback, int error, params object[] parameters)
		{
			byte[] bts = proto.Pack(method, callback, error, parameters);
			if(debug)
				CzfLog.Info ("Send:" + bts.Length);
			client.Send (bts);
		}

		public CzfNetManager (CzfProto proto, CzfNetListener listener, int iTimeout = 600)
		{
			this.iTimeout = iTimeout;
			this.proto = proto;
			allClient = new List<CzfNetClient> ();

			this.listener = listener;
			listener.OnAccept += OnAccept;

			current = this;
		}

		public void Start(){
			ThreadTool.TaskRun (CheckConnect);
			listener.Start ();
		}

		public void Stop(){
			looping = false;
		}

		void CheckConnect(){
			while (looping) {
				ThreadTool.TaskDelay (iTimeout * 1000 / 10);
				try{
					lock (allClientLock) {
						for (int i = 0; i < allClient.Count; i++) {
							var client = allClient [i];
							if ((DateTime.Now - client.lastRecive).TotalSeconds > iTimeout) {
								allClient.Remove (client);
								client.Close ();
								i--;
							}
						}
					}
				}catch(Exception e){
					CzfLog.Error ("CheckConnect", e);
				}
			}
		}

		void OnAccept(CzfNetListener listener, CzfNetClient client)
		{
			client.OnClose += OnClose;
			client.OnRecive += OnRecive;
			lock (allClientLock) {
				allClient.Add (client);
			}
			client.BeginRecive ();
			if(debug)
				CzfLog.Info (client.remoteEndPoint.ToString() + " Connect");
			if(OnClientConnect != null)
				OnClientConnect (this, client);
		}

		void OnClose(CzfNetClient client)
		{
			if (allClient.Contains (client)) {
				lock (allClientLock) {
					allClient.Remove (client);
				}
			}

			if(debug)
				CzfLog.Info (client.remoteEndPoint.ToString() + " DisConnect");
			if(OnClientClose != null)
				OnClientClose (this, client);
		}

		void OnRecive(CzfNetClient client, byte[] data)
		{
			if(debug)
				CzfLog.Info ("Receive:" + data.Length);
			CzfProto.client = client;
			var ret = proto.Unpack (data);
			if (ret != null) {
				if(debug)
					CzfLog.Info ("Send:" + ret.Length);
				client.Send (ret);
			}
		}
	}
}
